// 图层分组管理
let featureGroup
let poiFeatureGroup
let traceFeatureGroup
let popupFeatureGroup
// 地图
let map
// 图层信息Map, 加载图层信息的时候读取GeoJSON，并保存相关数据
let layerInfoMap
// 图层zoom配置
const ZOOM = {
    initZoom: 17,
    minZoom: 15,
    maxZoom: 22
}
// poi信息
let pois = []
// poi图层id和相关信息
let poiLayerMap
// 是否播放过
let played = false
// 轨迹map
let traceMap
// 轨迹图层(movingMarker, 用来控制暂停和停止)
let traceMarker
// 单独处理的图层
const ignoreList = ['poi', 'trace']
const geojsonKeys = [
    'boundary',
    'greenGround',
    'road',
    'academicBuildings',
    'lake',
    'diningRoom',
    'hospital',
    'playground',
    'playgroundLine',
    'bridge',
    'familyBuildings',
    'dormitory',
    'other',
    'poi',
    'trace'
]
init()
function init() {
    map = L.map('map', {
        maxZoom: ZOOM.maxZoom,
        minZoom: ZOOM.minZoom,
        zoomControl: false
    })
    map.setView([37.476238, 121.460097], ZOOM.initZoom)
    L.tileLayer(
        'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
    ).addTo(map)

    // 初始化数据
    featureGroup = L.featureGroup([]).addTo(map)
    poiFeatureGroup = L.featureGroup().addTo(map)
    traceFeatureGroup = L.featureGroup().addTo(map)
    popupFeatureGroup = L.featureGroup().addTo(map)

    layerInfoMap = new Map()
    traceMap = new Map()
    poiLayerMap = new Map()
    // 加载图层
    Util.loadAllGeoJSON(geojsonKeys).then(res => {
        // 加载geojson图层
        for (let i = 0; i < geojsonKeys.length; i++) {
            if (ignoreList.indexOf(geojsonKeys[i]) == -1) {
                buildByGeoJSON(res[i], geojsonKeys[i])
            }
        }
        map.on('zoom', e => {
            const zoom = map.getZoom()
            // 更新pois
            updatePois(zoom)
            // 更新geojson图层线条样式
            justifyLayerBorder(zoom)
        })
        // 景区点
        const points = res.find(item => item.name == 'point')
        pois = [...points.features]
        buildScreenPoints(points)
        // 缓存轨迹数据
        const trace = res.find(item => item.name == 'trace')
        for (let feature of trace.features) {
            const coors = Util.formatTraceData(feature.geometry.coordinates)
            traceMap.set(feature.properties.name, coors)
        }
    })
    // menu来自./js/menu.js
    buildLayerControlMenu(menu)
}

/**
 * 构建poi
 * @param {FeatureCollection} points
 */
function buildScreenPoints(points) {
    const { features } = points
    for (let i = 0; i < features.length; i++) {
        const feature = features[i]
        const { properties } = feature
        if (properties.showLevel <= ZOOM.initZoom) {
            buildScreenPoint(feature)
        }
    }
}

/**
 * 构建poi图层
 * @param {*} point
 * @return layerID
 */
function buildScreenPoint(feature) {
    const { properties } = feature
    const icon = L.icon({
        iconUrl: `${baseServer}/assets/icons/${properties.type}.svg`,
        iconSize: [18, 18],
        iconAnchor: [9, 9],
        className: 'rambler-marker-common'
    })
    // 构建marker
    // leaflet经纬度顺序不一样
    const coors = feature.geometry.coordinates[0]
    const marker = L.marker([coors[1], coors[0]], { icon: icon })
    // 构建popup
    const popup = L.popup({
        autoPan: false,
        className: 'rambler-popup-content'
    }).setContent(buildScreenPointPopup(properties))
    marker.bindPopup(popup)
    // 筛选工作放在外面，这里只执行构建图层，添加到组中，维护相关map和数组
    poiFeatureGroup.addLayer(marker)
    // map保存图层id和相关信息
    const layerId = poiFeatureGroup.getLayerId(marker)
    if (!poiLayerMap.has(layerId)) {
        poiLayerMap.set(layerId, properties)
    }
    return layerId
}

/**
 * 构建poi自定义弹窗dom
 * @param {*} properties
 * @returns popup DOM
 */
function buildScreenPointPopup(properties) {
    const container = document.createElement('div')
    container.className = 'rambler-popup-container'
    // 名称
    const title = document.createElement('p')
    title.innerHTML = `${properties.name}`
    title.className = 'rambler-popup-title'
    container.appendChild(title)
    // 预览图片
    const image = document.createElement('img')
    image.src = `${baseServer}/assets/imgs/${properties.name}.jpg`
    image.setAttribute('height', '200px')
    image.setAttribute('draggable', false)
    container.appendChild(image)
    return container
}

// 从features提取有效数据
function getPropertiesFromFeatures(feature) {
    const payload = {}
    Object.keys(feature.properties).forEach(key => {
        payload[key] = feature.properties[key]
    })
    return payload
}

// 基于geojson构建图层
function buildByGeoJSON(geoJSON, styleKey) {
    for (let i = 0; i < geoJSON.features.length; i++) {
        const feature = geoJSON.features[i]
        const layer = L.geoJSON(feature, {
            style: window.global.style[styleKey]
        })
        if (feature.properties.name)
            layer.bindPopup(feature.properties.name, {
                autoClose: false
            })
        featureGroup.addLayer(layer)
        const layerId = featureGroup.getLayerId(layer)
        const info = getPropertiesFromFeatures(feature)
        const center = layer.getBounds().getCenter()
        info['center'] = center
        info['layerName'] = styleKey
        info['bounds'] = layer.getBounds()
        // 缓存图层信息，后续搜索
        layerInfoMap.set(layerId, info)
    }
}

// 检索
function search(keywords) {
    // 搜索结果
    const searchResult = []
    Array.from(layerInfoMap.keys()).forEach(key => {
        const entry = layerInfoMap.get(key)
        if (entry.name && entry.name.indexOf(keywords) !== -1) {
            searchResult.push({
                layerID: key,
                name: entry.name
            })
        }
    })
    return searchResult
}

// document.querySelector('.search-input-inner').addEventListener(
//     'blur',
//     e => {
//         const searchResultDOM = document.querySelector('.search-result')
//         searchResultDOM.style.display = 'none'
//     },
//     true
// )

document.addEventListener('click', e => {
    const target = e.target
    const targetClassName = typeof target.className == 'string' ? target.className : ''
    const searchResultDOM = document.querySelector('.search-result')
    if (targetClassName !== 'search-result-li' && targetClassName != 'search-input-inner') {
        searchResultDOM.style.display = 'none'
    }
})

// blur和input时搜索
document.querySelector('.search-input-inner').addEventListener('input', handleSearch)
document.querySelector('.search-input-inner').addEventListener('focus', handleSearch)
function handleSearch() {
    const inputDOM = document.querySelector('.search-input-inner')
    const keywords = inputDOM.value.trim()
    const searchResultDOM = document.querySelector('.search-result ul')
    if (!keywords) {
        searchResultDOM.innerHTML = ''
        return
    }
    const resultArr = search(keywords)
    // 组装dom
    searchResultDOM.innerHTML = ''
    for (const result of resultArr) {
        const li = document.createElement('li')
        li.className = 'search-result-li'
        li.innerHTML = result.name
        li.setAttribute('layerID', result.layerID)
        searchResultDOM.appendChild(li)
    }
    searchResultDOM.parentNode.style.display = 'block'
}

// 点击跳转
document.querySelector('.search-result ul').addEventListener('click', e => {
    const path = e.composedPath()
    const target = Array.prototype.find.call(path, item => (item.nodeName = 'LI'))
    if (!target) {
        return
    }
    const layerID = target.getAttribute('layerID')
    const layer = featureGroup.getLayer(layerID)
    map.flyToBounds(layer.getBounds(), { duration: 1 })
    setTimeout(layer.togglePopup(), 1000)
})

// 处理checkbox选中和反选后加载图层以及删除图层操作
function handleLayerChange(checkbox) {
    const value = checkbox.value
    const checked = checkbox.checked
    // 加载GEOJSON的时候需要添加图层信息，
    const choosenLayers = value.split(',')
    if (checked) {
        checkbox.setAttribute('checked', true)
        // 添加图层，解析数据
        Util.loadAllGeoJSON(choosenLayers).then(res => {
            res.forEach((data, index) => {
                buildByGeoJSON(data, choosenLayers[index])
            })
        })
    } else {
        checkbox.setAttribute('checked', false)
        // 删除图层一系列图层，更新layerInfoMap
        const layers = []
        choosenLayers.forEach(choosenLayer => {
            layers.push(...getRelativeLayers(choosenLayer))
        })
        for (let layer of layers) {
            featureGroup.removeLayer(layer)
            layerInfoMap.delete(layer)
        }
    }
}

/**
 * 为方便搜索，在添加图层的时候将FeatureCollection拆解分别添加到group中
 * 比如教学楼可能有是个，分成了是个GeoJSON图层添加的
 * 这个函数用来获取一个geojson所有layerID
 * @param {*} name
 * @returns Array<layerID>
 */
function getRelativeLayers(name) {
    const layers = []
    Array.from(layerInfoMap.keys()).forEach(key => {
        const entry = layerInfoMap.get(key)
        if (entry.layerName && entry.layerName == name) {
            layers.push(key)
        }
    })
    return layers
}

// 调整图层线条样式
function justifyLayerBorder(zoom) {
    let weight = 0
    weight = (zoom - 15) * 0.5 + 0.5
    featureGroup.setStyle({
        weight: weight
    })
}

// 根据zoomLevel判断当前poi是否显示
function updatePois(zoom) {
    // 需要展示的poi名称
    const poiNames = pois
        .filter(poi => {
            const { properties } = poi
            return properties.showLevel <= zoom
        })
        .map(item => item.properties.name)
    const mapKeys = Array.from(poiLayerMap.keys())
    const deleteKeys = []
    poiNames.forEach(item => {
        let isExist = false
        for (const key of mapKeys) {
            // 删除多余的
            if (poiNames.indexOf(poiLayerMap.get(key).name) == -1) {
                if (deleteKeys.indexOf(key) == -1) {
                    deleteKeys.push(key)
                }
            }
            if (poiLayerMap.get(key).name == item) {
                isExist = true
            }
        }
        // 添加没有的图层
        if (!isExist) buildScreenPoint(pois.find(poi => poi.properties.name == item))
    })
    deleteKeys.forEach(key => {
        poiFeatureGroup.removeLayer(key)
        poiLayerMap.delete(key)
    })
}

/**
 * 切换路径, 绘制并fitBounds
 */
function handleTraceChoosed() {
    const layer = drawTrace()
    map.fitBounds(layer.getBounds())
}

/**
 * 绘制轨迹
 * @param {*} target
 */
function drawTrace() {
    played = false
    const target = document.querySelector('#trace')
    traceFeatureGroup.clearLayers()
    if (target.value == 'undefined') {
        return
    }
    const coors = traceMap.get(target.value)[0]
    const layer = L.polyline(coors, {
        color: '#5189f2',
        weight: 10
    })
    traceFeatureGroup.addLayer(layer)
    // 绘制轨迹装饰
    const decoratorLayer = L.polylineDecorator(layer, {
        patterns: [
            {
                offset: 10,
                endOffset: 10,
                repeat: 50,
                symbol: L.Symbol.arrowHead({ polygon: false })
            }
        ]
    })
    traceFeatureGroup.addLayer(decoratorLayer)
    return layer
}

/**
 * 播放轨迹
 * @param {*} start
 * @param {*} end
 */
function redrawTrace() {
    const target = document.querySelector('#trace')
    if (target.value == 'undefined') {
        alert('未选择路径')
        return
    }
    if (played) {
        return
    }
    played = true
    // 平移到起始点
    const coors = traceMap.get(target.value)[0]
    const startPoint = coors[0]
    map.flyTo(startPoint, 20, { duration: 1 })
    // 获取速度
    const selectedOption = Array.prototype.find.call(
        target.querySelectorAll('option'),
        item => item.selected == true
    )
    const speed = selectedOption.getAttribute('speed')
    setTimeout(() => {
        traceMarker = L.marker.movingMarker(startPoint, {
            coors: coors,
            speed: speed
        })
        traceFeatureGroup.addLayer(traceMarker)
    }, 1000)
}

/**
 * 响应[暂停]/[继续]
 */
function pauseOrPlay() {
    if (!traceMarker) {
        return
    }
    const target = document.querySelector('#controlBtn')
    const type = target.getAttribute('type')
    if (type == 'pause') {
        target.setAttribute('type', 'play')
        target.innerHTML = '继续'
        traceMarker.pause()
    } else {
        target.setAttribute('type', 'pause')
        target.innerHTML = '暂停'
        traceMarker.continue()
    }
}

// 停止
function stopTrace() {
    if (!played) {
        return
    }
    // 标识位重置
    played = false
    traceMarker.pause()
    // 清空图层
    traceFeatureGroup.clearLayers()
    // 重新制轨迹
    drawTrace()
}

// 定位建筑物范围, 并打开tooltip
function locateLayer(name) {
    // 清空之前保存的popup
    popupFeatureGroup.clearLayers()
    // lat维度, lng经度
    let northEast = {
        lat: 0,
        lng: 180
    }
    let southWest = {
        lat: 90,
        lng: 0
    }
    // bounds边界范围
    // const bounds = []
    const relativeLayerArrInfo = []
    Array.from(layerInfoMap.keys()).forEach(key => {
        const entry = layerInfoMap.get(key)
        if (entry.layerName && entry.layerName == name) {
            //  西北边界
            const _ne = entry.bounds.getNorthEast()
            if (_ne.lat > northEast.lat) {
                northEast.lat = _ne.lat
            }
            if (_ne.lng < northEast.lng) {
                northEast.lng = _ne.lng
            }
            // 东南边界
            const _sw = entry.bounds.getSouthWest()
            if (_sw.lat < southWest.lat) {
                southWest.lat = _sw.lat
            }
            if (_sw.lng > southWest.lng) {
                southWest.lng = _sw.lng
            }
            relativeLayerArrInfo.push({
                layerID: key,
                name: entry.name
            })
        }
    })
    if (relativeLayerArrInfo.length == 0) {
        alert('图层不存在或者已被移除')
        return
    }
    // 适配边界
    map.flyToBounds([northEast, southWest], { duration: 0.4 })
    // 打开popup
    relativeLayerArrInfo.forEach(info => {
        const layer = featureGroup.getLayer(info.layerID)
        L.popup({
            autoClose: false
        })
            .setLatLng(layer.getBounds().getCenter())
            .setContent(info.name || '未设置name属性')
            .openOn(popupFeatureGroup)
    })
}
